//
//  GWExecuteTool.m
//  Translate
//
//  Created by will on 14/12/19.
//  Copyright (c) 2014年 Pinguo. All rights reserved.
//

#import "GWExecuteTool.h"
#import "Taskit.h"
#import "GWDSYMFile.h"
#import "GWCrashFile.h"
#import "RegexKitLite.h"

#define kShellGrepCrashMemoryPath [[NSBundle mainBundle] pathForResource:@"grepcrashmemory" ofType:@"sh"]
#define kShellCat [[NSBundle mainBundle] pathForResource:@"cat" ofType:@"sh"]

@implementation GWExecuteTool
GWSingletonM(GWExecuteTool)

+ (void)executeShellPath:(NSString *)path param:(NSArray *)params success:(void (^)(NSString *output))success failure:(void (^)(NSString *error))failure
{
    NSAssert(path != nil, @"执行路径不能为空");
    
    if (path == nil)
    {
        if (failure)
        {
            failure(@"执行失败，执行路径不能为空 !!");
        }
        return;
    }

    // 实例化task
    Taskit *task = [Taskit task];
    task.launchPath = path;
    
    // 添加参数
    for (id param in params)
    {
        // 参数如果是数组，取出数组，拼接成字符串参数
        if ([param isKindOfClass:[NSArray class]])
        {
            NSArray *paramArr = (NSArray *)param;
            NSMutableString *paramStr = [[NSMutableString alloc] init];
            for (int i = 0; i < paramArr.count; i++) {
                [paramStr appendFormat:@"%@",paramArr[i]];
                if (i < paramArr.count - 1)
                {
                    [paramStr appendString:@" "];
                }
                
            }
                [task.arguments addObject:paramStr];
        }
        else
        {
            [task.arguments addObject:param];
        }
        
    }

    task.receivedOutputString = ^void(NSString *output) {
        // 回调
        if (success)
        {
            success(output);
        }
    };
    
    [task launch];
}

+ (void)symbolMemoryWithDsymPath:(NSString *)dSYMpath arch:(NSString *)arch address:(NSArray *)address success:(void (^)(NSDictionary *symbolDict))success failure:(void (^)(NSString *error))failure;
{
    [GWExecuteTool executeShellPath:kShellAtosPath param:@[arch,dSYMpath,address] success:^(NSString *output) {
        
        NSArray *symbolArr = [output componentsSeparatedByString:@"\n"];
        NSMutableDictionary *symbolDict = [NSMutableDictionary dictionary];
        
        if (symbolArr.count >= address.count)
        {
            for (int i = 0; i < address.count; i++)
            {
                NSString *symbolStr = symbolArr[i];
                NSString *addressShort = address[i];
                symbolDict[addressShort] = symbolStr;
            }
        }
        if (success)
        {
            success(symbolDict);
        }
    } failure:^(NSString *error) {
        if (failure)
        {
            failure([NSString stringWithFormat:@"符号化失败！%@",error]);
        }
    }];
}

+ (void)fetchDsymModelWithPath:(NSString *)dSYMpath success:(void (^)(GWDSYMFile *dSYM))success failure:(void (^)(NSString *error))failure
{
    [GWExecuteTool executeShellPath:kShellDwarfdumpPath param:@[dSYMpath] success:^(NSString *output) {
        GWDSYMFile *d = [[GWDSYMFile alloc] initWithSrcUUID:output];
        if (success)
        {
            success(d);
        }
    } failure:^(NSString *error) {
        if (failure)
        {
            failure(error);
        }
    }];
}

+ (void)fetchCrashModelWithCrashPath:(NSString *)crashPath dSYMPath:(NSString *)dsymPath success:(void (^)(GWCrashFile *crash))success failure:(void (^)(NSString *error))failure;
{
    [GWExecuteTool fetchDsymModelWithPath:dsymPath success:^(GWDSYMFile *dSYM) {
        GWCrashFile *cf = [[GWCrashFile alloc] init];
        cf.path = crashPath;
        cf.trueName = dSYM.trueName;
        
        [GWExecuteTool executeShellPath:kShellGrepCrashPath param:@[crashPath,dSYM.trueName] success:^(NSString *output) {
// output
//0xbe000 - 0x1169fff Camera360 armv7  <f26a496d939f3a208b08b6d4287d706e> /var/mobile/Containers/Bundle/Application/7B218DC0-E438-4F48-90BE-BBCFCF619421/Camera36.app/Camera360
            
//            NSArray *uuidArr = [output componentsMatchedByRegex:@"<[a-zA-Z0-9]{32}>"];
            NSArray *uuidArr = [output componentsSeparatedByString:@" "];
            NSAssert(uuidArr.count == 8, @"dSYM文件字UUID字符串有变化，模型化crash文件出错！");
            if (uuidArr.count == 8)
            {
                NSString *uuidStr = uuidArr[6];
                // 截取UUID去掉<>括号
                cf.uuid = [uuidStr substringWithRange:NSMakeRange(1, uuidStr.length - 2)];
                cf.arch = uuidArr[4];
                
                // 判断uuid是否匹配
                NSString *uuidDsym = dSYM.uuidDict[cf.arch];
                if ([uuidDsym isEqualToString:cf.uuid])
                {
                    cf.isMatchDsymUUID = YES;
                }
            }
            [GWExecuteTool fetchCrashMemorysPath:crashPath trueName:dSYM.trueName success:^(NSDictionary *memorysDict) {
                cf.memoryDictSrc = memorysDict;
                
                [GWExecuteTool executeShellPath:kShellCat param:@[crashPath] success:^(NSString *output) {
                    cf.content = output;
                    if (success)
                    {
                        success(cf);
                    }
                } failure:^(NSString *error) {
                    
                }];

            } failure:^(NSString *error) {
                
            }];
            

            
        } failure:^(NSString *error) {
            
        }];

    } failure:^(NSString *error) {
        if (failure)
        {
            failure(@"执行脚本出错");
        }
    }];
}

#pragma mark - 私有方法

+ (void)fetchCrashMemorysPath:(NSString *)path trueName:(NSString *)trueName success:(void (^)(NSDictionary *memorysDict))success failure:(void (^)(NSString *error))failure;
{
    [GWExecuteTool executeShellPath:kShellGrepCrashMemoryPath param:@[trueName,path] success:^(NSString *output) {
        NSArray *memoryArr = [output componentsSeparatedByString:@"\n"];
        NSMutableDictionary *memoryDict = [NSMutableDictionary dictionary];
        for (NSString *msrc in memoryArr)
        {
            // 匹配内存地址
            NSString *memoryShort = [msrc stringByMatching:@"0x[0-9a-f]{8}"];
            if (memoryShort != nil)
            {
                memoryDict[memoryShort] = msrc;
            }
        }
        if (success)
        {
            success(memoryDict);
        }
    } failure:^(NSString *error) {
        if (failure != nil && error != nil)
        {
            failure(error);
        }
    }];
}

@end
